package org.geoserver.jtilecache.util;

import java.io.IOException;
import java.io.InputStream;

import java.util.HashSet;
import java.util.Properties;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.geoserver.jtilecache.service.wms.WMSParameters;


public class Configuration {

	private static Log log = LogFactory.getLog(org.geoserver.jtilecache.util.Configuration.class);

	private static final String NAMESPACE = "org.geoserver.jtilecache";
	private static final String PROPERTY_FILENAME = "jtilecache.properties";

	private static final String DEFAULT_SERVER = "http://localhost:8080/geoserver/wms";
	private static final String DEFAULT_SERVICE = "wms";
	private static final String DEFAULT_CACHE = NAMESPACE + ".cache.JCS";
	private static final String DEFAULT_RESOLUTION_CONSTRAINT = "NO";
	private static final String DEFAULT_FORWARD_ON_ERROR = "NO";

	private Properties props = null;

	private WMSParameters wmsparams = null;
	private String server = null;
	private String service = null;
	private String cache = null;
	private Set resolutions = null;
	private boolean forward_errors;


//	 Make Configuration a singleton
	private static final Configuration singleton_inst = new Configuration();

	private Configuration() {
		readProperties();
		setServer();
		setService();
		setCacheType();
		setWMSParameters();
		setResolutionConstraints();
		setForwardOnError();
	}

	public static Configuration getInstance() {
		return singleton_inst;
	}

	private void readProperties() {
		props = new Properties();

		InputStream in = Configuration.class.getResourceAsStream("/" + PROPERTY_FILENAME);
		if(in != null) {
			log.debug("Found " + PROPERTY_FILENAME + " file.");
			try {
				props.load(in);
			} catch(IOException ioe) {
				log.error("Could not read " + PROPERTY_FILENAME + " file: ", ioe);
			}
		} else {
			log.error("Could not find " + PROPERTY_FILENAME + "!");
		}
	}


	// TODO: configuration should be layer-based: specify a list of layers,
	// and then configure them

	private void setWMSParameters() {

		wmsparams = new WMSParameters();

		if(this.service == null) {
			setService();
		}

		wmsparams.setAllFromString(
				props.getProperty(NAMESPACE + "." + this.service + "." + WMSParameters.REQUEST_PARAM.toLowerCase()),
				props.getProperty(NAMESPACE + "." + this.service + "." + WMSParameters.VERSION_PARAM.toLowerCase()),
				props.getProperty(NAMESPACE + "." + this.service + "." + WMSParameters.TILED_PARAM.toLowerCase()),
				props.getProperty(NAMESPACE + "." + this.service + "." + WMSParameters.SRS_PARAM.toLowerCase()),
				props.getProperty(NAMESPACE + "." + this.service + "." + WMSParameters.LAYER_PARAM.toLowerCase()),
				props.getProperty(NAMESPACE + "." + this.service + "." + WMSParameters.STYLES_PARAM.toLowerCase()),
				props.getProperty(NAMESPACE + "." + this.service + "." + WMSParameters.BBOX_PARAM.toLowerCase()),
				props.getProperty(NAMESPACE + "." + this.service + "." + WMSParameters.ORIGIN_PARAM.toLowerCase()),
				props.getProperty(NAMESPACE + "." + this.service + "." + WMSParameters.HEIGHT_PARAM.toLowerCase()),
				props.getProperty(NAMESPACE + "." + this.service + "." + WMSParameters.WIDTH_PARAM.toLowerCase()),
				props.getProperty(NAMESPACE + "." + this.service + "." + WMSParameters.IMAGE_TYPE_PARAM.toLowerCase()),
				props.getProperty(NAMESPACE + "." + this.service + "." + WMSParameters.ERROR_TYPE_PARAM.toLowerCase())
		);

		log.info("Default WMS Parameters set to: " + wmsparams.toString());

	}

	private void setServer() {
		this.server = props.getProperty(NAMESPACE + ".server", DEFAULT_SERVER);
		log.info("Server set to: " + this.server);
	}

	private void setService() {
		this.service = props.getProperty( NAMESPACE + ".service", DEFAULT_SERVICE).toLowerCase();
		log.info("Service set to: " + this.service);
	}

	private void setCacheType() {
		this.cache = props.getProperty(NAMESPACE + ".cache", DEFAULT_CACHE);
		log.info("Cache type set to: " + this.cache);
	}

	@SuppressWarnings("unchecked")
	private void setResolutionConstraints() {
		String res_str = props.getProperty(NAMESPACE + ".resolution_constraint", DEFAULT_RESOLUTION_CONSTRAINT);
		log.info("Resolution constraint set to: " + res_str);

		if(res_str.equalsIgnoreCase("NO") || res_str.equalsIgnoreCase("NONE")) {
			this.resolutions = null;
		} else {
			this.resolutions = new HashSet();
			String[] res_array = res_str.split(",");

			for(int i = 0; i < res_array.length; ++i) {
				this.resolutions.add(Double.valueOf(res_array[i]));
			}

			if(log.isTraceEnabled()) {
				log.trace("Parsed resolutions as: " + this.resolutions.toString());
			}
		}
	}

	private void setForwardOnError() {
		String forward = props.getProperty( NAMESPACE + ".forward_on_error", DEFAULT_FORWARD_ON_ERROR);
		this.forward_errors = (forward.equalsIgnoreCase("YES") || forward.equalsIgnoreCase("TRUE"));

		if(this.forward_errors) {
			log.info("Forwarding on error enabled.");
		} else {
			log.info("Forwarding on error disabled.");
		}
	}

	// TODO: make generic service instead of wms
	public WMSParameters getParameters() {
		return this.wmsparams;
	}

	public String getServer() {
		return this.server;
	}

	public String getService() {
		return this.service;
	}

	public String getCacheType() {
		return this.cache;
	}

	public Set getResolutionConstraints() {
		return this.resolutions;
	}

	public boolean getForwardOnError() {
		return this.forward_errors;
	}

}
